package udpserver

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"strings"
	"time"
)


var (
	//最大任务队列数
	MaxWorker = 1000
)

//有效载荷
type Payload struct {
	Num int
	Info string
}

//待执行的工作
type Job struct {
	Payload Payload
}

//任务队列channal
var JobQueue chan Job

//执行任务的工作者单元
type Worker struct {
	WorkerPool chan chan Job //工作者池--每个元素是一个工作者的私有任务channal
	JobChannel chan Job      //每个工作者单元包含一个任务管道 用于获取任务
	quit       chan bool     //退出信号
	no         int           //编号
}


// 停止信号
func (w Worker) Stop() {
	go func() {
		w.quit <- true
	}()
}


//调度中心
type Dispatcher struct {
	//工作者池(任务队列池)
	WorkerPool chan chan Job
	//工作者单元数量
	MaxWorkers int
}


//创建调度中心
func NewDispatcher(maxWorkers int) *Dispatcher {
	//创建工作者池，存放待处理的任务队列，maxWorkers为最大任务队列数
	pool := make(chan chan Job, maxWorkers)
	return &Dispatcher{WorkerPool: pool, MaxWorkers: maxWorkers}
}




//创建一个新工作者单元
func NewWorker(workerPool chan chan Job, no int) Worker {
	//fmt.Println("创建一个新工作者单元")
	return Worker{
		WorkerPool: workerPool,
		JobChannel: make(chan Job),
		quit:       make(chan bool),
		no:         no,
	}
}




//循环  监听任务和执行任务
func (w Worker) Start(Db *sql.DB) {

	//启动协程，监听任务
	go func() {
		for {
			// register the current worker into the worker queue.
			//工作者放回工作者池
			w.WorkerPool <- w.JobChannel
			//fmt.Println("w.WorkerPool <- w.JobChannel", w)
			select {
			case job := <-w.JobChannel:
				//fmt.Println("job := <-w.JobChannel")
				// 收到任务,执行打印任务

				//fmt.Println("安全帽字符串：",job.Payload.Info)
				//&&0000000，加速度传感器信息，定位类别，￥GPS，纬度，经度，海拔，净高，定位方式，定位状态码，包长，标签类别，设备ID，设备所属公司
				capinfo := job.Payload.Info
				capinfoarray := strings.Split(capinfo, ",")
				timeUnix:=time.Now().Unix()
				timeStr:=time.Now().Format("2006-01-02 15:04:05")
				//添加ＧＰＳ数据
				sql := "insert into gps_info(data,labelid,company,timestamp,datatimestr) values('%s','%s','%s','%d','%s')"
					sql1 := fmt.Sprintf(sql, capinfoarray[4]+","+capinfoarray[5], capinfoarray[12], capinfoarray[13], timeUnix, timeStr)
					result, _ := Db.Exec(sql1)    //返回执行结果  //执行sql语句
					n, _ := result.RowsAffected() //获取受影响的记录数
					FileLogs.Info("受影响的记录数是", n)
				//执行任务需要1秒时间
				//time.Sleep(1 * time.Microsecond)

			case <-w.quit:
				// 收到退出信号，停止监听，结束该协程
				return
			}
		}
	}()
}


//调度，任务分发
func (d *Dispatcher) dispatch() {
	for {
		select {
		//从任务队列中获取任务
		case job := <-JobQueue:
			//fmt.Println("job := <-JobQueue:")
			go func(job Job) {
				//等待空闲worker (任务多的时候会阻塞这里)
				//从（10个）工作者池中获取一个任务队列channel，
				jobChannel := <-d.WorkerPool
				//fmt.Println("jobChannel := <-d.WorkerPool", reflect.TypeOf(jobChannel))
				// 将任务放到上述woker的私有任务channal中，jobChannel是一个无缓冲信道，每次只能放一个任务
				jobChannel <- job
				//fmt.Println("jobChannel <- job")
			}(job)
		}
	}
}



//工作者池的初始化，注意Run为Dispatcher结构体指针的方法，所以此方法内对Dispathcer的修改在方法外也可见
func (d *Dispatcher) Run(Db *sql.DB) {

	// starting n number of workers
	//创建10个工作者单元
	for i := 1; i < d.MaxWorkers+1; i++ {
		worker := NewWorker(d.WorkerPool, i)
		worker.Start(Db)
	}
	go d.dispatch()
}




////新建任务并放入任务队列
//func addQueue() {
//	for i := 0; i < 1000000; i++ {
//		fmt.Println("当前请求数：",i)
//		// 新建一个任务
//		payLoad := Payload{Num: 1, Test:"this is Test string"}
//		work := Job{Payload: payLoad}
//		// 任务放入任务队列channal
//		fmt.Println("新任务入队列！")
//		JobQueue <- work
//		//fmt.Println("队列总长度:",cap(JobQueue))
//		//fmt.Println("队列未消费任务数量:",len(JobQueue))
//		//fmt.Println("JobQueue <- work")
//		fmt.Println("当前协程数:", runtime.NumGoroutine())
//		//time.Sleep(1 * time.Second)
//	}
//}



func StartJobqueue() {
	//log := udplogs.NewLogger(10000)
	//log.SetLogger("file", `{"filename":"udplogs/test.log", "maxlines" : 1000,"maxsize"  : 10240}`) // 设置日志记录方式：本地文件记录
	//log.SetLevel(udplogs.LevelDebug)     // 设置日志写入缓冲区的等级
	//log.EnableFuncCallDepth(true)     // 输出log时能显示输出文件名和行号（非必须）
	// 数据源语法："用户名:密码@[连接方式](主机名:端口号)/数据库名"
	Db, _ := sql.Open("mysql", "root:Askme#268200@tcp(192.168.1.109:3306)/FindMe?parseTime=true&loc=Local")
	//设置连接数据库的参数 1.驱动名固定写法，2 数据源名称@符号后边如果是tcp协议，那么可以省略不写
	//返回db和一个错误.
	defer Db.Close() //关闭数据库
	//上边只是设置参数，并未真正连接

	//真正连接
	err := Db.Ping() //连接数据库

	if err != nil { //判断成功失败
		fmt.Println(err)
		//log.Debug(err)
		//log.Debug("数据库连接失败")

		//如果连接失败 先检查数据库服务是否已经启动 net start mysql启动数据库
		return
	}


	//建立任务队列，每个任务队列中可以放10个任务
	JobQueue = make(chan Job, 10)
	//fmt.Println("成功建立任务队列！")
	//新建任务分发器
	dispatcher := NewDispatcher(MaxWorker)
	//fmt.Println("成功建立任务分发器！")
	dispatcher.Run(Db)
	//time.Sleep(1 * time.Second)
	//go addQueue()
	for{
		//fmt.Println("===========停顿1000秒===========")
		time.Sleep(1000 * time.Second)
	}
}

